/*
 * This source is from OpenZipkin.
 *
 * Copyright 2015-2018 The OpenZipkin Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package scouter.util.zipkin;

/**
 * @author Gun Lee (gunlee01@gmail.com) on 24/11/2018
 */
public class HexCodec {
    /**
     * Parses a 1 to 32 character lower-hex string with no prefix into an unsigned long, tossing any
     * bits higher than 64.
     */
    public static long lowerHexToUnsignedLong(String lowerHex) {
        int length = lowerHex.length();
        if (length < 1 || length > 32) throw isntLowerHexLong(lowerHex);

        // trim off any high bits
        int beginIndex = length > 16 ? length - 16 : 0;

        return lowerHexToUnsignedLong(lowerHex, beginIndex);
    }

    /**
     * Parses a 16 character lower-hex string with no prefix into an unsigned long, starting at the
     * spe index.
     */
    public static long lowerHexToUnsignedLong(String lowerHex, int index) {
        long result = 0;
        for (int endIndex = Math.min(index + 16, lowerHex.length()); index < endIndex; index++) {
            char c = lowerHex.charAt(index);
            result <<= 4; //  result = result << 4
            if (c >= '0' && c <= '9') {
                result |= c - '0'; // result = result | c - '0'
            } else if (c >= 'a' && c <= 'f') {
                result |= c - 'a' + 10;
            } else {
                throw isntLowerHexLong(lowerHex);
            }
        }
        return result;
    }

    static NumberFormatException isntLowerHexLong(String lowerHex) {
        throw new NumberFormatException(
                lowerHex + " should be a 1 to 32 character lower-hex string with no prefix");
    }

    HexCodec() {}
}
